package hygprs

import (
	"bytes"
	"encoding/binary"
	"github.com/axgle/mahonia"
	"sync/atomic"
	"time"
)

type Fields struct {
	Packet
	indexes map[byte]int // 索引:记录每个字段的起始位置，为空时表示需要重新生成索引
	ep      int          // 已索引字段的终点位置
	Revise  map[byte]int // 索引修正:生成索引后会用修正值覆盖已生成的索引
}

func MakeFields(p Packet) Fields {
	return Fields{
		Packet: p,
		Revise: map[byte]int{},
	}
}

/*
生成索引
当需要索引但索引为空时，生成索引
*/
func (p *Fields) Indexing() {
	h := func(data []byte, bp, ep int) (map[byte]int, int) {
		m := make(map[byte]int)
		offset := bp
		for offset < ep {
			b := data[offset]
			if _, has := m[b]; has {
				return m, offset
			}
			switch b {
			case LineID, BusID, OperatorID, Unix, 0x07, 0x08, 0x11, 0x13, 0x14, 0x15, 0x16, 0x17, 0x1b, 0x1e, 0x1f, 0x20, 0x21, 0x23,
				0x24, 0x27, 0x31, 0x32, 0x33, 0x34, 0x36, 0x37, 0x40, 0x41, 0x42, 0x46, 0x47, 0x48, 0x49, 0x10:
				if offset+4 < ep {
					m[b] = offset + 1
					offset += 5
				}
			case 0x03, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x18, 0x1a, 0x1d, 0x22, 0x25, 0x26, 0x35, 0x38, 0x43, 0x44, 0x45, 0x4a, 0x4c, 0xef:
				if offset+1 < ep {
					m[b] = offset + 1
					offset += 2
				}
			case 0x09, 0x0a, 0x19, 0x1c, 0x28, 0x29, 0x30, 0x39, 0x4b:
				if offset+2 < ep {
					m[b] = offset + 1
					offset += 3
				}
			case 0x12, 0xf1, 0xf2:
				m[b] = offset + 1
				return m, ep
			default:
				return m, offset
			}
		}
		return m, 0
	}
	ep := len(p.Data) + PositionChecksum
	if p.Type == 0xaf || p.Type == 0xf3 {
		// 0xaf包没有校验和
		ep = len(p.Data)
	}
	p.indexes, p.ep = h(p.Data, PositionData, ep)
	for k, v := range p.Revise {
		p.indexes[k] = v
	}
}

/*
重置索引
当修改涉及到包结构时，重置索引
*/
func (p *Fields) Reset() {
	p.indexes = nil
	p.ep = 0
}

func (p *Fields) Byte(f byte) byte {
	if p.indexes == nil {
		p.Indexing()
	}
	index, has := p.indexes[f]
	if !has {
		return 0
	}
	return p.Data[index]
}

func (p *Fields) SetByte(f byte, v byte) bool {
	if p.indexes == nil {
		p.Indexing()
	}
	index, has := p.indexes[f]
	if !has {
		return false
	}
	p.Data[index] = v
	return true
}

func (p *Fields) Uint16(f byte) uint16 {
	if p.indexes == nil {
		p.Indexing()
	}
	index, has := p.indexes[f]
	if !has {
		return 0
	}
	return ToUint16(p.Data[index:])
}

func (p *Fields) SetUint16(f byte, v uint16) bool {
	if p.indexes == nil {
		p.Indexing()
	}
	index, has := p.indexes[f]
	if !has {
		return false
	}
	binary.BigEndian.PutUint16(p.Data[index:], v)
	return true
}

func (p *Fields) Uint32(f byte) uint32 {
	if p.indexes == nil {
		p.Indexing()
	}
	index, has := p.indexes[f]
	if !has {
		return 0
	}
	return ToUint32(p.Data[index:])
}

func (p *Fields) SetUint32(f byte, v uint32) bool {
	if p.indexes == nil {
		p.Indexing()
	}
	index, has := p.indexes[f]
	if !has {
		return false
	}
	binary.BigEndian.PutUint32(p.Data[index:], v)
	return true
}

func (p *Fields) LineID() uint32 {
	return p.Uint32(LineID)
}

func (p *Fields) SetLineID(v uint32) bool {
	return p.SetUint32(LineID, v)
}

func (p *Fields) BusID() uint32 {
	return p.Uint32(BusID)
}

func (p *Fields) SetBusID(v uint32) bool {
	return p.SetUint32(BusID, v)
}

func (p *Fields) DeviceType() byte {
	return p.Byte(DeviceType)
}

func (p *Fields) SetDeviceType(v byte) bool {
	return p.SetByte(DeviceType, v)
}

func (p *Fields) OperatorID() uint32 {
	return p.Uint32(OperatorID)
}

func (p *Fields) SetOperatorID(v uint32) bool {
	return p.SetUint32(OperatorID, v)
}

func (p *Fields) DriverKH() uint32 {
	return p.Uint32(DriverKH)
}

func (p *Fields) SetDriverKH(v uint32) bool {
	return p.SetUint32(DriverKH, v)
}

func (p *Fields) Unix() uint32 {
	return p.Uint32(Unix)
}

func (p *Fields) SetUnix(v uint32) bool {
	return p.SetUint32(Unix, v)
}

func (p *Fields) Longitude() uint32 {
	return p.Uint32(Longitude)
}

func (p *Fields) SetLongitude(v uint32) bool {
	return p.SetUint32(Longitude, v)
}

func (p *Fields) Latitude() uint32 {
	return p.Uint32(Latitude)
}

func (p *Fields) SetLatitude(v uint32) bool {
	return p.SetUint32(Latitude, v)
}

func (p *Fields) Angle() uint16 {
	return p.Uint16(Angle)
}

func (p *Fields) SetAngle(v uint16) bool {
	return p.SetUint16(Angle, v)
}

func (p *Fields) Speed() uint16 {
	return p.Uint16(Speed)
}

func (p *Fields) SetSpeed(v uint16) bool {
	return p.SetUint16(Speed, v)
}

const (
	RDDown = 0x00
	RDUp   = 0x01
)

func (p *Fields) RunDirection() byte {
	return p.Byte(ShiftType)
}

func (p *Fields) SetRunDirection(v byte) bool {
	return p.SetByte(ShiftType, v)
}

func (p *Fields) StationNo() byte {
	return p.Byte(Station)
}

func (p *Fields) SetStationNo(v byte) bool {
	return p.SetByte(Station, v)
}

const (
	RAManual = 0x00
	RAAuto   = 0x01
)

func (p *Fields) ReportAuto() byte {
	return p.Byte(ReportStationAuto)
}

func (p *Fields) SetReportAuto(v byte) bool {
	return p.SetByte(ReportStationAuto, v)
}

const (
	RTReport   = 0x00
	RTForecast = 0x01
	RTRunning  = 0x02
)

func (p *Fields) ReportType() byte {
	return p.Byte(ReportStationType)
}

func (p *Fields) SetReportType(v byte) bool {
	return p.SetByte(ReportStationType, v)
}

func (p *Fields) AlarmType() byte {
	return p.Byte(AlarmType)
}

func (p *Fields) SetAlarmType(v byte) bool {
	return p.SetByte(AlarmType, v)
}

func (p *Fields) DispatcherID() uint32 {
	return p.Uint32(Dispatcher)
}

// a0的调度员编号
func (p *Fields) SetDispatcherID(v uint32) bool {
	return p.SetUint32(Dispatcher, v)
}

const (
	Out  = 0x00
	Into = 0x01
)

func (p *Fields) IO() byte {
	return p.Byte(EnterOrLeave)
}

func (p *Fields) SetIO(v byte) bool {
	return p.SetByte(EnterOrLeave, v)
}

type ConfirmType byte

const (
	ConfirmAuto   ConfirmType = 0x00
	ConfirmManual ConfirmType = 0x03
)

func (p *Fields) SetConfirmType(v ConfirmType) bool {
	return p.SetByte(Confirm, byte(v))
}

func (p *Fields) Unique() uint32 {
	return p.Uint32(PostBackID)
}

func (p *Fields) SetUnique(v uint32) bool {
	return p.SetUint32(PostBackID, v)
}

func (p *Fields) GroundID() uint16 {
	return p.Uint16(GroundStationNumber)
}

func (p *Fields) SetGroundID(v uint16) bool {
	return p.SetUint16(GroundStationNumber, v)
}

// 日期时间(36、37字段)
func (p *Fields) DateTime() time.Time {
	dv := int(p.Uint32(0x36))
	tv := int(p.Uint32(0x37))
	return time.Date(dv/10000, time.Month(dv/100%100), dv%100, tv/10000, tv/100%100, tv%100, 0, time.Local)
}

// 获取不定长项的内容 例如 0x12项
func (p *Fields) GetBytes(b byte) []byte {
	if p.indexes == nil {
		p.Indexing()
	}
	index, has := p.indexes[b]
	if !has {
		return []byte{}
	}
	return p.Data[index : len(p.Data)-5]
}

func (p *Fields) Memo() []byte {
	if p.indexes == nil {
		p.Indexing()
	}
	index, has := p.indexes[0xf2]
	if !has {
		return []byte{}
	}
	return p.Data[index : len(p.Data)-5]
}

func (p *Fields) MemoString() string {
	return mahonia.NewDecoder("GBK").ConvertString(string(p.Memo()))
}

func (p *Fields) SetBytes(k byte, v []byte) bool {
	if p.indexes == nil {
		p.Indexing()
	}
	index, has := p.indexes[k]
	if !has {
		return false
	}
	copy(p.Data[index:], v)
	return true
}
func (p *Fields) SetBytesAppend(k byte, vs []uint32) bool {
	if p.indexes == nil {
		p.Indexing()
	}
	index, has := p.indexes[k]
	if !has {
		return false
	}

	var bs []byte
	for _, v := range vs {
		b := FromUint32(v)
		bs = append(bs, append([]byte{k}, b...)...)
	}

	p.Data = bytes.Replace(p.Data, p.Data[index-1:index+5], bs, 1)

	//copy(p.Data[index-1:], vs)

	return true
}

/*
*设置包序号 从1 开始
 */
func (p *Fields) SetSerialNumber() {
	v := atomic.LoadInt32(&PacketSeq)
	p.SerialNumber = uint16(v + 1)
	//如果取值未65535 则设置为0 重新递增包序号
	if v == 65534 {
		atomic.StoreInt32(&PacketSeq, 0)
	} else {
		atomic.AddInt32(&PacketSeq, 1)
	}
}
